package client

import (
	"chess_platform/internal/alisdk"
	. "chess_platform/internal/common"
	"chess_platform/internal/login"
	"chess_platform/internal/token"
	"chess_platform/models/client"
	"chess_platform/models/h5"
	"chess_platform/models/partner"
	"chess_platform/models/pc"
	"fmt"
	"github.com/astaxie/beego/orm"
	"time"
)

//[client]登录
type LoginController struct {
	BaseController
}

type GameToken struct {
	Uid        int64
	CreateTime int64
	SvrKey     string
}

func GenerateGameToken(uid int64) (gt GameToken) {
	gt.Uid = uid
	gt.CreateTime = time.Now().Unix()
	gt.SvrKey = Md5sum(fmt.Sprintf("%v%d%d", Secret.Md5Key, gt.Uid, gt.CreateTime))
	return
}

func (b *LoginController) URLMapping() {
	b.Mapping("Login", b.Login)
	b.Mapping("Test", b.Test)
	b.Mapping("TestSever", b.TestSever)
	b.Mapping("Captcha", b.Captcha)
	b.Mapping("WeChatLogin", b.WeChatLogin)
	b.Mapping("XianLiaoLogin", b.XianLiaoLogin)
	b.Mapping("VisitorLogin", b.VisitorLogin)
	b.Mapping("UidLogin", b.UidLogin)
}

// @Title 发送短信验证码
// @Description 发送短信验证码
// @Param   phone body    string  true      "手机号"
// @Success 0 {string} captcha 验证码
// @Failure 400
// @Failure 404
// @router /captcha [post]
func (b *LoginController) Captcha() {
	type Params struct {
		Phone string
	}
	var p Params
	if !b.DecodeParams(&p) {
		return
	}
	b.Valid.Required(p.Phone, "phone").Message("手机号不能为空")
	b.Valid.Phone(p.Phone, "phone").Message("请输入正确的手机号")
	if !b.VerifyParamsError() {
		return
	}
	captcha, msg, err := alisdk.SendSMSCaptcha(p.Phone, Sms.SmsSignName, Sms.SmsCode, KeyClientPhone,
		MemCache, CaptchaCacheExpire, CaptchaSendAgainExpire)
	if err != nil {
		LogClient.Error(b.SystemError(err.Error()))
		return
	}
	if msg != "OK" {
		b.ResponseFail(msg)
		return
	}
	LogClient.Debug(fmt.Sprintf("Captcha:%v", captcha))
	b.ResponseSuccess("已发送")
}

// @Title 手机登录
// @Description 手机登录
// @Param   phone         body    string  true      "手机号用于登录"
// @Param   password      body    string  true      "密码"
// @Param   captcha       body    string  true      "短信验证码"
// @Param   device_id     body    string  true      "设备ID"
// @Param   model         body    string  true      "设备类型(设备型号,如vivo X7Plus)"
// @Success 0 {string} token 字符串
// @Failure 400
// @Failure 404
// @router /login [post]
func (b *LoginController) Login() {
	if !b.IsServerStop() {
		return
	}

	type Params struct {
		Model    string `json:"model"`
		DeviceId string `json:"device_id"`
		Phone    string `json:"phone"`
		Password string `json:"password"`
		Captcha  string `json:"captcha"`
	}
	var p Params
	if !b.DecodeParams(&p) {
		return
	}
	b.Valid.Required(p.Phone, "phone").Message("手机号不能为空")
	b.Valid.Phone(p.Phone, "phone").Message("错误的手机号")
	b.Valid.Required(p.Password, "password").Message("密码不能为空")
	b.Valid.MinSize(p.Password, 6, "password").Message("密码长度为6-15个字符")
	b.Valid.MaxSize(p.Password, 15, "password").Message("密码长度为6-15个字符")
	b.Valid.Required(p.Captcha, "captcha").Message("验证码不能为空")
	b.Valid.Numeric(p.Captcha, "captcha").Message("验证码为6位数字")
	b.Valid.Length(p.Captcha, 6, "captcha").Message("验证码为6位数字")
	if !b.VerifyParamsError() {
		return
	}
	err, ok := alisdk.VerifySMSCaptcha(p.Phone, p.Captcha, KeyClientPhone, MemCache)
	if !ok {
		b.Res.Code = ErrCaptchaVerify
		b.Res.Msg = err.Error()
		b.Response()
		return
	}

	passport, err := client.PassportInfoByTelephone(p.Phone)
	if err != nil {
		LogClient.Error(b.SystemError(err.Error()))
		return
	}
	if passport == nil {
		b.Res.Code = ErrNotFound
		b.Res.Msg = MsgErrUserNotFound
		b.Response()
		return
	}
	if passport.Phone != p.Phone || passport.Password != Md5sum(p.Password) {
		b.Res.Code = ErrUserOrPassword
		b.Res.Msg = MsgErrPhoneOrPassword
		b.Response()
		return
	}

	tokenStr := token.Create(passport.Uid, 0, TokenClient, nil)
	//把token存在redis里,可以验证是否此帐号在一个地方登录
	/*
		key := fmt.Sprintf("%v%v", KeyClientTokenCache, passport.Uid)
		RedisCache.Put(key, tokenStr, time.Duration(Secret.ClientTokenCacheExpire)*time.Second)
		deviceIdKey := fmt.Sprintf("%v%v", KeyClientDeviceId, passport.Uid)
		RedisCache.Put(deviceIdKey, p.DeviceId, time.Duration(Secret.ClientTokenCacheExpire)*time.Second)
	*/

	b.Res.Code = Success
	b.Res.Msg = MsgLoginSuccess
	b.Res.Token = tokenStr
	b.Res.Data = map[string]interface{}{
		"game_token":    GenerateGameToken(passport.Uid),
		"web_server_ip": fmt.Sprintf("%v:%v", PlatformConf.IP, PlatformConf.HttpPort),
	}
	b.Response()
	client.SendFullMail(passport.Uid)

	ip := b.Ctx.Input.IP()
	if len(b.Ctx.Input.Proxy()) > 0 {
		ip = b.Ctx.Input.Proxy()[0]
	}
	log := map[string]interface{}{
		"login_time": time.Now().Unix(),
		"uid":        passport.Uid,
		"ip":         ip,
		"model":      p.Model,
		"device_id":  p.DeviceId,
	}
	client.NewLoginLog(log)
	return
}

// @Title 微信登录
// @Description 微信登录
// @Param   access_token  body    string  true      "微信access_token"
// @Param   open_id       body    string  true      "微信用户open_id"
// @Param   version_id    body    string  true      "版本号"
// @Param   device_id     body    string  true      "设备ID"
// @Param   model         body    string  true      "设备类型(设备型号,如vivo X7Plus)"
// @Success 0 {string} token
// @Failure 400
// @Failure 404
// @router /weChat-login [post]
func (b *LoginController) WeChatLogin() {
	if !b.IsServerStop() {
		return
	}
	type Params struct {
		AccessToken string `json:"access_token" valid:"Required"`
		OpenId      string `json:"open_id" valid:"Required"`
		VersionId   string `json:"version_id" valid:"Required"`
		Model       string `json:"model" valid:"Required"`
		DeviceId    string `json:"device_id" valid:"Required"`
	}
	var p Params
	if !b.DecodeParams(&p, LogLogin) {
		return
	}
	if !b.ValidParams(&p, LogLogin) {
		return
	}

	weChat, err := login.GetWeChatUserInfo(p.AccessToken, p.OpenId)
	if err != nil {
		LogLogin.Error(b.LoginRetry(err.Error()))
		return
	}
	if weChat == nil {
		b.Res.Code = ErrNotFound
		b.Res.Msg = MsgErrUserNotFound
		LogLogin.Warning(fmt.Sprintf("OpenID:%v在微信服务器里没有找到此用户", p.OpenId))
		b.Response()
		return
	}
	if weChat.OpenID == "" {
		b.Res.Code = ErrWeChatLoginFail
		b.Res.Msg = "微信登录已过期,请重新登录"
		LogLogin.Warning(fmt.Sprintf("OpenID:%v,微信登录已过期,请重新登录", p.OpenId))
		b.Response()
		return
	}
	ip := b.Ctx.Input.IP()
	if len(b.Ctx.Input.Proxy()) > 0 {
		ip = b.Ctx.Input.Proxy()[0]
	}
	LogClient.Debug(fmt.Sprintf("ip:%v,用户(昵称:%v)的直接源IP:%v,代理IP:%v",
		ip, weChat.NickName, b.Ctx.Input.IP(), b.Ctx.Input.Proxy()))
	u := map[string]interface{}{
		"loginip":    ip,
		"logintime":  time.Now().Unix(),
		"lversionid": p.VersionId,
		"model":      p.Model,
		"nickname":   FilterEmoji(weChat.NickName),
		"sex":        weChat.Sex,
		"imageurl":   weChat.HeadImgURL,
	}

	passport := map[string]interface{}{
		"access_token": p.AccessToken,
		"type":         LOGIN_TYPE_WECHAT,
	}

	pp, err := client.IsPassportExistByOpenID(p.OpenId)
	if CheckNoExist(err) { //doesn't exist
		LogClient.Debug(fmt.Sprintf("玩家openId:%v未注册,现在注册", p.OpenId))
		passport["open_id"] = p.OpenId
		passport["union_id"] = weChat.UnionID

		o := orm.NewOrm()
		o.Begin()
		defer o.Rollback()
		uid := client.GetNormalPlayerUid(o) //从数据库里取出一个uid
		if uid == 0 {
			LogLogin.Warning(fmt.Sprintf("OpenID:%v,注册时获取新uid失败,uid可能已经用完了", p.OpenId))
			o.Rollback()
			b.ResponseFail("注册失败")
			return
		}
		passport["uid"] = uid
		_, err = client.NewPassport(passport, o)
		if err != nil {
			LogLogin.Error(fmt.Sprintf("OpenID:%v,注册时写入passport失败:%v", p.OpenId, err.Error()))
			o.Rollback()
			LogClient.Error(b.DatabaseError(err.Error()))
			return
		}
		u["uid"] = uid
		//创建时间
		u["rtime"] = time.Now().Unix()

		//玩家注册成功赠送钻石
		rule, err := h5.RuleByType(RulePlayerRegisterDiamond)
		if err == nil {
			u["rmcard"] = rule.Amount
		}
		r2, err := h5.RuleByType(RulePlayerRegisterCoin)
		if err == nil {
			u["coin"] = r2.Amount
		}
		_, err = client.NewUser(u, o)
		if err != nil {
			LogLogin.Error(fmt.Sprintf("OpenID:%v,注册时写入user表失败:%v", p.OpenId, err.Error()))
			o.Rollback()
			LogClient.Error(b.DatabaseError(err.Error()))
			return
		}
		o.Commit()

		//注册成功,有赠送钻石,需要写记录
		if rule.Amount != 0 {
			err := pc.DoSystemDiamond(SysClientGiveUid, -rule.Amount, uid, SysOpRegister, -1, Player)
			if err != nil {
				LogLogin.Error(fmt.Sprintf("注册成功,从客户端系统赠送帐号:%v扣钻石数:%v到玩家(ID:%v)失败,操作类型为:%v,失败日志:%v",
					SysClientGiveUid, rule.Amount, uid, SysOpRegister, err))
				LogClient.Error(fmt.Sprintf("从客户端系统赠送帐号:%v扣钻石数:%v到玩家(ID:%v)失败,操作类型为:%v,失败日志:%v",
					SysClientGiveUid, rule.Amount, uid, SysOpRegister, err))
			}
		}

		client.SendFullMail(uid)
		//刚注册，肯定是今天第一次登录,info字段为1表示每天首次登录
		tokenStr := token.Create(uid, 0, TokenClient, 1)
		b.Res.Code = Success
		b.Res.Msg = MsgLoginSuccess
		b.Res.Token = tokenStr
		b.Res.Data = map[string]interface{}{
			"game_token":    GenerateGameToken(uid),
			"web_server_ip": fmt.Sprintf("%v:%v", PlatformConf.IP, PlatformConf.HttpPort),
		}
		b.Response()
		partner.UpdateAgentPlayerRelationByUnionId(uid, weChat.UnionID)

		/*
			//把token存在redis里,可以验证是否此帐号在一个地方登录
			key := fmt.Sprintf("%v%v", KeyClientTokenCache, uid)
			RedisCache.Put(key, tokenStr, time.Duration(Secret.ClientTokenCacheExpire)*time.Second)
			deviceIdKey := fmt.Sprintf("%v%v", KeyClientDeviceId, uid)
			RedisCache.Put(deviceIdKey, p.DeviceId, time.Duration(Secret.ClientTokenCacheExpire)*time.Second)
		*/
	} else if err == nil && pp.Uid != 0 { //exist
		LogClient.Debug(fmt.Sprintf("玩家(ID:%v)openId:%v已注册,现在登录", pp.Uid, p.OpenId))
		ppUser, err := client.IsUserFrozenAndLoginTime(pp.Uid)
		if err != nil {
			LogLogin.Error(fmt.Sprintf("uid:%v,登录时获取用户信息时失败:%v", pp.Uid, err.Error()))
			LogClient.Error(b.DatabaseError(err.Error()))
			return
		}
		if ppUser == nil {
			LogLogin.Error(b.SystemError(fmt.Sprintf("uid:%v,不存在user表,而存在于passport表", pp.Uid)))
			LogClient.Error(b.SystemError(fmt.Sprintf("此用户(UID:%v)不存在user表,而存在于passport表", pp.Uid)))
			return
		}
		//判断用户是否被冻结了
		if ppUser.Frozen == 1 {
			b.Res.Code = ErrUserFrozen
			b.Res.Msg = "用户被冻结,请联系客服,冻结理由:" + ppUser.FrozenReason
			b.Response()
			return
		}
		//消除每天首次分享奖励标识
		client.ClearBit(pp.Uid, ppUser.LoginTime, BitShareApp)

		//判断用户是否今天首次登录,1-为首次登录
		var firstTime int
		if !IsToday(ppUser.LoginTime) {
			firstTime = 1
		}
		_, err = client.UpdatePassport(passport, pp.Uid)
		if err != nil {
			LogLogin.Error(fmt.Sprintf("uid:%v,更新passport表时失败:%v,其中data:%#v", pp.Uid, err.Error(), passport))
			LogClient.Error(b.DatabaseError(err.Error()))
			return
		}

		//更新玩家信息
		_, err = client.UpdateUser(u, pp.Uid)
		if err != nil {
			LogLogin.Error(fmt.Sprintf("uid:%v,更新user表时失败:%v,其中data:%#v", pp.Uid, err.Error(), u))
			LogClient.Error(b.DatabaseError(err.Error()))
			return
		}
		client.SendFullMail(pp.Uid)
		//level可能用于区分用户等级,如VIP用户
		tokenStr := token.Create(pp.Uid, 0, TokenClient, firstTime)
		b.Res.Code = Success
		b.Res.Msg = MsgLoginSuccess
		b.Res.Token = tokenStr
		b.Res.Data = map[string]interface{}{
			"game_token":    GenerateGameToken(pp.Uid),
			"web_server_ip": fmt.Sprintf("%v:%v", PlatformConf.IP, PlatformConf.HttpPort),
		}
		b.Response()

		//登录时把用户信息缓存删除
		keyUserInfo := fmt.Sprintf("%v%v", KeyClientUserInfo, pp.Uid)
		DelCache(RedisCache, keyUserInfo)

		/*
			//把token存在redis里,可以验证是否此帐号在一个地方登录
			key := fmt.Sprintf("%v%v", KeyClientTokenCache, pp.Uid)
			RedisCache.Put(key, tokenStr, time.Duration(Secret.ClientTokenCacheExpire)*time.Second)
			deviceIdKey := fmt.Sprintf("%v%v", KeyClientDeviceId, pp.Uid)
			RedisCache.Put(deviceIdKey, p.DeviceId, time.Duration(Secret.ClientTokenCacheExpire)*time.Second)
		*/
	} else { //error happen, system busy try again
		LogLogin.Error(fmt.Sprintf("OpenID:%v,在数据库里查找此openId时失败:%v", p.OpenId, err.Error()))
		LogClient.Error(b.LoginRetry(err.Error()))
	}

	log := map[string]interface{}{
		"login_time": time.Now().Unix(),
		"uid":        pp.Uid,
		"ip":         ip,
		"device_id":  p.DeviceId,
		"model":      p.Model,
	}
	client.NewLoginLog(log)
	return
}

// @Title 闲聊登录
// @Description 闲聊登录
// @Param   access_token  body    string  true      "闲聊access_token"
// @Param   open_id       body    string  true      "闲聊用户open_id"
// @Param   version_id    body    string  true      "版本号"
// @Param   model         body    string  true      "设备类型(设备型号)"
// @Param   device_id     body    string  true      "设备ID"
// @Success 0 {string} token
// @Failure 400
// @Failure 404
// @router /xianliao-login [post]
func (b *LoginController) XianLiaoLogin() {
	if !b.IsServerStop() {
		return
	}
	type Params struct {
		AccessToken string `json:"access_token" valid:"Required"`
		VersionId   string `json:"version_id" valid:"Required"`
		Model       string `json:"model" valid:"Required"`
		DeviceId    string `json:"device_id" valid:"Required"`
	}
	var p Params
	if !b.DecodeParams(&p) {
		return
	}
	if !b.ValidParams(&p) {
		return
	}
	//访问闲聊服务器
	weChat, err := login.GetXianLiaoUserInfo(p.AccessToken)
	if err != nil {
		LogClient.Error(b.LoginRetry(err.Error()))
		return
	}
	if weChat == nil {
		b.Res.Code = ErrNotFound
		b.Res.Msg = MsgErrUserNotFound
		b.Response()
		return
	}
	LogClient.Debug(fmt.Sprintf("访问闲聊服务器:%#v\n", weChat))
	if weChat.Data.OpenId == "" {
		b.Res.Code = ErrWeChatLoginFail
		b.Res.Msg = "闲聊登录已过期,请重新登录"
		b.Response()
		return
	}
	ip := b.Ctx.Input.IP()
	if len(b.Ctx.Input.Proxy()) > 0 {
		ip = b.Ctx.Input.Proxy()[0]
	}
	u := map[string]interface{}{
		"loginip":    ip,
		"logintime":  time.Now().Unix(),
		"lversionid": p.VersionId,
		"model":      p.Model,
		"nickname":   FilterEmoji(weChat.Data.Nickname),
		//"sex":        weChat.Sex,
		"imageurl": weChat.Data.SmallAvatar,
	}

	passport := map[string]interface{}{
		"type": LOGIN_TYPE_XianLiao,
	}

	pp, err := client.IsPassportExistByOpenID(weChat.Data.OpenId)
	if CheckNoExist(err) { //doesn't exist
		LogClient.Debug(fmt.Sprintf("玩家openId:%v未注册,现在注册", weChat.Data.OpenId))
		passport["open_id"] = weChat.Data.OpenId

		o := orm.NewOrm()
		o.Begin()
		defer o.Rollback()
		uid := client.GetNormalPlayerUid(o) //从数据库里取出一个uid
		if uid == 0 {
			o.Rollback()
			b.ResponseFail("注册失败")
			return
		}
		passport["uid"] = uid
		_, err = client.NewPassport(passport, o)
		if err != nil {
			o.Rollback()
			LogClient.Error(b.DatabaseError(err.Error()))
			return
		}
		u["uid"] = uid
		//创建时间
		u["rtime"] = time.Now().Unix()

		//玩家注册成功赠送钻石
		rule, err := h5.RuleByType(RulePlayerRegisterDiamond)
		if err == nil {
			u["rmcard"] = rule.Amount
		}
		r2, err := h5.RuleByType(RulePlayerRegisterCoin)
		if err == nil {
			u["coin"] = r2.Amount
		}
		_, err = client.NewUser(u, o)
		if err != nil {
			o.Rollback()
			LogClient.Error(b.DatabaseError(err.Error()))
			return
		}
		o.Commit()

		//注册成功,有赠送钻石,需要写记录
		if rule.Amount != 0 {
			err := pc.DoSystemDiamond(SysClientGiveUid, -rule.Amount, uid, SysOpRegister, -1, Player)
			if err != nil {
				LogClient.Error(fmt.Sprintf("从客户端系统赠送帐号:%v扣钻石数:%v到玩家(ID:%v)失败,操作类型为:%v,失败日志:%v",
					SysClientGiveUid, rule.Amount, uid, SysOpRegister, err))
			}
		}

		client.SendFullMail(uid)
		//刚注册，肯定是今天第一次登录,info字段为1表示每天首次登录
		tokenStr := token.Create(uid, 0, TokenClient, 1)
		b.Res.Code = Success
		b.Res.Msg = MsgLoginSuccess
		b.Res.Token = tokenStr
		b.Res.Data = map[string]interface{}{
			"game_token":    GenerateGameToken(uid),
			"web_server_ip": fmt.Sprintf("%v:%v", PlatformConf.IP, PlatformConf.HttpPort),
		}
		b.Response()
		/*
			//把token存在redis里,可以验证是否此帐号在一个地方登录
			key := fmt.Sprintf("%v%v", KeyClientTokenCache, uid)
			RedisCache.Put(key, tokenStr, time.Duration(Secret.ClientTokenCacheExpire)*time.Second)
			deviceIdKey := fmt.Sprintf("%v%v", KeyClientDeviceId, uid)
			RedisCache.Put(deviceIdKey, p.DeviceId, time.Duration(Secret.ClientTokenCacheExpire)*time.Second)
		*/
	} else if err == nil && pp.Uid != 0 { //exist
		LogClient.Debug(fmt.Sprintf("玩家(ID:%v)openId:%v已注册,现在登录", pp.Uid, weChat.Data.OpenId))
		ppUser, err := client.IsUserFrozenAndLoginTime(pp.Uid)
		if err != nil {
			LogClient.Error(b.DatabaseError(err.Error()))
			return
		}
		if ppUser == nil {
			LogClient.Error(b.SystemError(fmt.Sprintf("此用户(UID:%v)不存在user表,而存在于passport表", pp.Uid)))
			return
		}
		//判断用户是否被冻结了
		if ppUser.Frozen == 1 {
			b.Res.Code = ErrUserFrozen
			b.Res.Msg = "用户被冻结,请联系客服,冻结理由:" + ppUser.FrozenReason
			b.Response()
			return
		}
		//消除每天首次分享奖励标识
		client.ClearBit(pp.Uid, ppUser.LoginTime, BitShareApp)
		//判断用户是否今天首次登录,1-为首次登录
		var firstTime int
		if !IsToday(ppUser.LoginTime) {
			firstTime = 1
		}
		_, err = client.UpdatePassport(passport, pp.Uid)
		if err != nil {
			LogClient.Error(b.DatabaseError(err.Error()))
			return
		}

		//更新玩家信息
		_, err = client.UpdateUser(u, pp.Uid)
		if err != nil {
			LogClient.Error(b.DatabaseError(err.Error()))
			return
		}
		client.SendFullMail(pp.Uid)
		//level可能用于区分用户等级,如VIP用户
		tokenStr := token.Create(pp.Uid, 0, TokenClient, firstTime)
		b.Res.Code = Success
		b.Res.Msg = MsgLoginSuccess
		b.Res.Token = tokenStr
		b.Res.Data = map[string]interface{}{
			"game_token":    GenerateGameToken(pp.Uid),
			"web_server_ip": fmt.Sprintf("%v:%v", PlatformConf.IP, PlatformConf.HttpPort),
		}
		b.Response()

		//登录时把用户信息缓存删除
		keyUserInfo := fmt.Sprintf("%v%v", KeyClientUserInfo, pp.Uid)
		DelCache(RedisCache, keyUserInfo)

		/*
			//把token存在redis里,可以验证是否此帐号在一个地方登录
			key := fmt.Sprintf("%v%v", KeyClientTokenCache, pp.Uid)
			RedisCache.Put(key, tokenStr, time.Duration(Secret.ClientTokenCacheExpire)*time.Second)
			deviceIdKey := fmt.Sprintf("%v%v", KeyClientDeviceId, pp.Uid)
			RedisCache.Put(deviceIdKey, p.DeviceId, time.Duration(Secret.ClientTokenCacheExpire)*time.Second)
		*/
	} else { //error happen, system busy try again
		LogClient.Error(b.LoginRetry(err.Error()))
	}

	log := map[string]interface{}{
		"login_time": time.Now().Unix(),
		"uid":        pp.Uid,
		"ip":         ip,
		"device_id":  p.DeviceId,
		"model":      p.Model,
	}
	client.NewLoginLog(log)
	return
}

// @Title 游客登录
// @Description 游客登录
// @Param   device_id     body    string  true      "设备号"
// @Param   version_id    body    string  true      "版本号"
// @Param   model         body    string  true      "设备类型(设备型号)"
// @Param   device_id     body    string  true      "设备ID"
// @Success 0 {string} token
// @Failure 400
// @Failure 404
// @router /visitor-login [post]
func (b *LoginController) VisitorLogin() {
	if !b.IsServerStop() {
		return
	}
	/*
		if !b.IsDevelopMode() {
			return
		}
	*/

	type Params struct {
		DeviceId  string `json:"device_id" valid:"Required"`
		VersionId string `json:"version_id" valid:"Required"`
		Model     string `json:"model" valid:"Required"`
	}
	var p Params
	if !b.DecodeParams(&p) {
		return
	}
	if !b.ValidParams(&p) {
		return
	}

	passport := map[string]interface{}{
		"open_id": p.DeviceId,
		"type":    LOGIN_TYPE_VISITOR,
	}
	ip := b.Ctx.Input.IP()
	if len(b.Ctx.Input.Proxy()) > 0 {
		ip = b.Ctx.Input.Proxy()[0]
	}
	u := map[string]interface{}{
		"sex":        1,
		"loginip":    ip,
		"logintime":  time.Now().Unix(),
		"lversionid": p.VersionId,
		"model":      p.Model,
	}

	pp, err := client.IsPassportExistByOpenID(p.DeviceId)
	if CheckNoExist(err) { //doesn't exist

		o := orm.NewOrm()
		o.Begin()
		defer o.Rollback()
		uid := client.GetNormalPlayerUid(o) //从数据库里取出一个uid
		if uid == 0 {
			o.Rollback()
			b.ResponseFail("注册失败")
			return
		}
		passport["uid"] = uid
		_, err := client.NewPassport(passport, o)
		if err != nil {
			o.Rollback()
			LogClient.Error(b.DatabaseError(err.Error()))
			return
		}
		u["uid"] = uid
		u["nickname"] = fmt.Sprintf("游客%v", uid)
		//创建时间
		u["rtime"] = time.Now().Unix()
		//玩家注册成功赠送钻石
		rule, err := h5.RuleByType(RulePlayerRegisterDiamond)
		if err == nil {
			u["rmcard"] = rule.Amount
		}
		r2, err := h5.RuleByType(RulePlayerRegisterCoin)
		if err == nil {
			u["coin"] = r2.Amount
		}
		_, err = client.NewUser(u, o)
		if err != nil {
			o.Rollback()
			LogClient.Error(b.DatabaseError(err.Error()))
			return
		}
		o.Commit()

		tokenStr := token.Create(uid, 0, TokenClient, 1)

		/*
			//把token存在redis里,可以验证是否此帐号在一个地方登录
			key := fmt.Sprintf("%v%v", KeyClientTokenCache, uid)
			RedisCache.Put(key, tokenStr, time.Duration(Secret.ClientTokenCacheExpire)*time.Second)
			deviceIdKey := fmt.Sprintf("%v%v", KeyClientDeviceId, uid)
			RedisCache.Put(deviceIdKey, p.DeviceId, time.Duration(Secret.ClientTokenCacheExpire)*time.Second)
		*/

		client.SendFullMail(uid)

		b.Res.Code = Success
		b.Res.Msg = MsgLoginSuccess
		b.Res.Token = tokenStr
		b.Res.Data = map[string]interface{}{
			"game_token":    GenerateGameToken(uid),
			"web_server_ip": fmt.Sprintf("%v:%v", PlatformConf.IP, PlatformConf.HttpPort),
		}
		b.Response()

		//注册成功,有赠送钻石,需要写记录
		if rule.Amount != 0 {
			err := pc.DoSystemDiamond(SysClientGiveUid, -rule.Amount, uid, SysOpRegister, -1, Player)
			if err != nil {
				LogClient.Error(fmt.Sprintf("从客户端系统赠送帐号:%v扣钻石数:%v到玩家(ID:%v)失败,操作类型为:%v,失败日志:%v",
					SysClientGiveUid, rule.Amount, uid, SysOpRegister, err))
			}
		}
	} else if err == nil && pp.Uid != 0 { //exist
		ppUser, err := client.IsUserFrozenAndLoginTime(pp.Uid)
		if err != nil {
			LogClient.Error(b.DatabaseError(err.Error()))
			return
		}
		if ppUser == nil {
			LogClient.Error(b.SystemError(fmt.Sprintf("此用户(UID:%v)不存在user表,而存在于passport表", pp.Uid)))
			return
		}
		if ppUser.Frozen == 1 {
			b.Res.Code = ErrUserFrozen
			b.Res.Msg = "用户被冻结,请联系客服,冻结理由:" + ppUser.FrozenReason
			b.Response()
			return
		}
		//消除每天首次分享奖励标识
		client.ClearBit(pp.Uid, ppUser.LoginTime, BitShareApp)
		//判断用户是否今天首次登录
		var firstTime int
		if !IsToday(ppUser.LoginTime) {
			firstTime = 1
		}

		_, err = client.UpdateUser(u, pp.Uid)
		if err != nil {
			LogClient.Error(b.DatabaseError(err.Error()))
			return
		}

		//登录时把用户信息缓存删除
		keyUserInfo := fmt.Sprintf("%v%v", KeyClientUserInfo, pp.Uid)
		DelCache(RedisCache, keyUserInfo)

		tokenStr := token.Create(pp.Uid, 0, TokenClient, firstTime)

		/*
			//把token存在redis里,可以验证是否此帐号在一个地方登录
			key := fmt.Sprintf("%v%v", KeyClientTokenCache, pp.Uid)
			RedisCache.Put(key, tokenStr, time.Duration(Secret.ClientTokenCacheExpire)*time.Second)
			deviceIdKey := fmt.Sprintf("%v%v", KeyClientDeviceId, pp.Uid)
			RedisCache.Put(deviceIdKey, p.DeviceId, time.Duration(Secret.ClientTokenCacheExpire)*time.Second)
		*/

		client.SendFullMail(pp.Uid)

		b.Res.Code = Success
		b.Res.Msg = MsgLoginSuccess
		b.Res.Token = tokenStr
		b.Res.Data = map[string]interface{}{
			"game_token":    GenerateGameToken(pp.Uid),
			"web_server_ip": fmt.Sprintf("%v:%v", PlatformConf.IP, PlatformConf.HttpPort),
		}
		b.Response()
	} else { //error happen, system busy try again
		LogClient.Error(b.LoginRetry(err.Error()))
	}

	log := map[string]interface{}{
		"login_time": time.Now().Unix(),
		"uid":        pp.Uid,
		"ip":         ip,
		"model":      p.Model,
		"device_id":  p.DeviceId,
	}
	client.NewLoginLog(log)
	return
}

// @Title 游客登录
// @Description 游客登录
// @Param   uid           body    int     true      "玩家uid"
// @Param   device_id     body    string  true      "设备号"
// @Param   version_id    body    string  true      "版本号"
// @Param   model         body    string  true      "设备类型(设备型号)"
// @Param   device_id     body    string  true      "设备ID"
// @Success 0 {string} token
// @Failure 400
// @Failure 404
// @router /uid-login [post]
func (b *LoginController) UidLogin() {
	if !b.IsServerStop() {
		return
	}
	/*
		if !b.IsDevelopMode() {
			return
		}
	*/

	type Params struct {
		Uid       int64  `json:"uid" valid:"Required"`
		DeviceId  string `json:"device_id"`
		VersionId string `json:"version_id"`
		Model     string `json:"model"`
	}
	var p Params
	if !b.DecodeParams(&p) {
		return
	}
	if !b.ValidParams(&p) {
		return
	}

	ip := b.Ctx.Input.IP()
	if len(b.Ctx.Input.Proxy()) > 0 {
		ip = b.Ctx.Input.Proxy()[0]
	}

	//登录时把用户信息缓存删除
	keyUserInfo := fmt.Sprintf("%v%v", KeyClientUserInfo, p.Uid)
	DelCache(RedisCache, keyUserInfo)

	tokenStr := token.Create(p.Uid, 0, TokenClient, 0)

	b.Res.Code = Success
	b.Res.Msg = MsgLoginSuccess
	b.Res.Token = tokenStr
	b.Res.Data = map[string]interface{}{
		"game_token":    GenerateGameToken(p.Uid),
		"web_server_ip": fmt.Sprintf("%v:%v", PlatformConf.IP, PlatformConf.HttpPort),
	}
	b.Response()

	log := map[string]interface{}{
		"login_time": time.Now().Unix(),
		"uid":        p.Uid,
		"ip":         ip,
		"model":      p.Model,
		"device_id":  p.DeviceId,
	}
	client.NewLoginLog(log)
	return
}

// @Title 测试服务器反应速度
// @Description 测试服务器反应速度
// @Success 0 {string} token
// @Failure 400
// @Failure 404
// @router /test-server [post]
func (b *LoginController) TestSever() {
	b.Res.Data = map[string]interface{}{
		"web_server_ip": fmt.Sprintf("%v:%v", PlatformConf.IP, PlatformConf.HttpPort),
	}
	b.ResponseSuccess()
}

// @Title 代码测试
// @Description 代码测试
// @Success 0 {string} token
// @Failure 400
// @Failure 404
// @router /test [get]
func (b *LoginController) Test() {
	//url, err := partner.MakePfQRCode(676732,
	//	"http://thirdwx.qlogo.cn/mmopen/vi_32/IUeRRqTWdyriaRuBPzibiayC3Da0PKmvrYIk4dwmZoBtiak0RTvNf2e7jhSfZSLqOy7RawSrBAMDz8jhbjA6UkH6IQ/132", "name")

	url, err := partner.MakePfQRCode(676732,
		"http://thirdwx.qlogo.cn/mmopen/vi_32/71eyYkibpzRbEbqiblsV6VP8WHe6zYXdNmMvT7wHR94abxG0Rsriaaeq1vHQXNicEQhK1tuPIOKRoSS9sIfmI8KXpA/132", "name")
	b.Res.Data = url
	if err != nil {
		b.ResponseFail(err.Error())
	}
	b.ResponseSuccess()

}
